home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
016a
/
gofer221.zip
/
COMPILER.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-20
|
42KB
|
1,400 lines
/* --------------------------------------------------------------------------
* compiler.c: Copyright (c) Mark P Jones 1991. All rights reserved.
* See goferite.h for details and conditions of use etc...
* Gofer version 2.21 November 1991
*
* Last updated 01/11/91 mpj
*
* This is the Gofer compiler, handling translation of typechecked code to
* `kernel' language, elimination of pattern matching and translation to
* super combinators (lambda lifting).
* ------------------------------------------------------------------------*/
#include "prelude.h"
#include "storage.h"
#include "connect.h"
Bool useConformality = TRUE; /* TRUE => check pat-bind conform'ty*/
Addr inputCode; /* Address of compiled code for expr*/
/* --------------------------------------------------------------------------
* Local function prototypes:
* ------------------------------------------------------------------------*/
static Cell local translate Args((Cell));
static Void local transPair Args((Pair));
static Void local transTriple Args((Triple));
static Void local transAlt Args((Cell));
static Void local transCase Args((Cell));
static List local transBinds Args((List));
static Cell local transRhs Args((Cell));
static Cell local mkConsList Args((List));
static Cell local expandLetrec Args((Cell));
static Cell local transComp Args((Cell,List,Cell));
static Bool local refutable Args((Cell));
static Cell local refutePat Args((Cell));
static List local remPat Args((Cell,Cell,List));
static List local remPat1 Args((Cell,Cell,List));
static Cell local pmcTerm Args((Int,List,Cell));
static Cell local pmcAp Args((Int,List,Pair));
static Cell local pmcPair Args((Int,List,Pair));
static Cell local pmcTriple Args((Int,List,Triple));
static Cell local pmcVar Args((List,Text));
static Void local pmcLetrec Args((Int,List,Pair));
static Cell local pmcVarDef Args((Int,List,List));
static Void local pmcFunDef Args((Int,List,Triple));
static Cell local match Args((Int,List,List));
static Void local tidyHdPat Args((Offset,Cell));
static Cell local hdDiscr Args((List));
static Int local discrKind Args((Cell));
static Cell local matchVar Args((Int,List,List,Cell));
static Cell local matchCon Args((Int,List,List,Cell));
static List local addConTable Args((Cell,Cell,List));
static Cell local makeCases Args((Int,List,List));
static Cell local matchInt Args((Int,List,List,Cell));
static List local addOffsets Args((Int,Int,List));
static Cell local mkSwitch Args((List,Pair));
static Cell local joinSw Args((Int,List));
static Bool local canFail Args((Cell));
static Cell local lift Args((Int,List,Cell));
static Void local liftAp Args((Int,List,Pair));
static Void local liftPair Args((Int,List,Pair));
static Void local liftTriple Args((Int,List,Triple));
static Void local liftAlt Args((Int,List,Cell));
static Cell local liftVar Args((List,Cell));
static Cell local liftLetrec Args((Int,List,Cell));
static Void local liftFundef Args((Int,List,Triple));
static Void local solve Args((List));
static Cell local preComp Args((Cell));
static Cell local preCompPair Args((Pair));
static Cell local preCompTriple Args((Triple));
static Void local preCompCase Args((Pair));
static Cell local preCompOffset Args((Int));
static Void local compileGlobalFunction Args((Pair));
static Void local compileMemberFunction Args((Name));
static Void local newGlobalFunction Args((Name,Int,List,Int,Cell));
/* --------------------------------------------------------------------------
* Transformation: Convert input expressions into a less complex language
* of terms using only LETREC, AP, constants and vars.
* Also remove pattern definitions on lhs of eqns.
* ------------------------------------------------------------------------*/
static Cell local translate(e) /* Translate expression: */
Cell e; {
switch (whatIs(e)) {
case LETREC : snd(snd(e)) = translate(snd(snd(e)));
return expandLetrec(e);
case COND : transTriple(snd(e));
break;
case AP : transPair(e);
break;
case UNIT :
case TUPLE :
case NAME :
case SELECT :
case VAROPCELL :
case VARIDCELL :
case DICTVAR :
case DICTCELL :
case INTCELL :
case FLOATCELL :
case STRCELL :
case CHARCELL : break;
case FINLIST : mapOver(translate,snd(e));
return mkConsList(snd(e));
case LISTCOMP : return transComp(translate(fst(snd(e))),
snd(snd(e)),
nameNil);
case ESIGN : return translate(fst(snd(e)));
case CASE : { Cell nv = inventVar();
mapProc(transCase,snd(snd(e)));
return ap(LETREC,
pair(singleton(pair(nv,snd(snd(e)))),
ap(nv,translate(fst(snd(e))))));
}
case LAMBDA : { Cell nv = inventVar();
transAlt(snd(e));
return ap(LETREC,
pair(singleton(pair(
nv,
singleton(snd(e)))),
nv));
}
default : internal("translate");
}
return e;
}
static Void local transPair(pr) /* Translate each component in a */
Pair pr; { /* pair of expressions. */
fst(pr) = translate(fst(pr));
snd(pr) = translate(snd(pr));
}
static Void local transTriple(tr) /* Translate each component in a */
Triple tr; { /* triple of expressions. */
fst3(tr) = translate(fst3(tr));
snd3(tr) = translate(snd3(tr));
thd3(tr) = translate(thd3(tr));
}
static Void local transAlt(e) /* Translate alt: */
Cell e; { /* ([Pat], Rhs) ==> ([Pat], Rhs') */
snd(e) = transRhs(snd(e));
}
static Void local transCase(c) /* Translate case: */
Cell c; { /* (Pat, Rhs) ==> ([Pat], Rhs') */
fst(c) = singleton(fst(c));
snd(c) = transRhs(snd(c));
}
static List local transBinds(bs) /* Translate list of bindings: */
List bs; { /* eliminating pattern matching on */
List newBinds; /* lhs of bindings. */
for (newBinds=NIL; nonNull(bs); bs=tl(bs)) {
if (isVar(fst(hd(bs)))) {
mapProc(transAlt,snd(hd(bs)));
newBinds = cons(hd(bs),newBinds);
}
else
newBinds = remPat(fst(snd(hd(bs))),
snd(snd(hd(bs)))=transRhs(snd(snd(hd(bs)))),
newBinds);
}
return newBinds;
}
static Cell local transRhs(rhs) /* Translate rhs: removing line nos */
Cell rhs; {
switch (whatIs(rhs)) {
case LETREC : snd(snd(rhs)) = transRhs(snd(snd(rhs)));
return expandLetrec(rhs);
case GUARDED : mapOver(snd,snd(rhs)); /* discard line number */
mapProc(transPair,snd(rhs));
return rhs;
default : return translate(snd(rhs)); /* discard line number */
}
}
static Cell local mkConsList(es) /* Construct expression for list es */
List es; { /* using nameNil and nameCons */
if (isNull(es))
return nameNil;
else
return ap(ap(nameCons,hd(es)),mkConsList(tl(es)));
}
static Cell local expandLetrec(root) /* translate LETREC with list of */
Cell root; { /* groups of bindings (from depend. */
Cell e = snd(snd(root)); /* analysis) to use nested LETRECs */
List bss = fst(snd(root));
Cell temp;
if (isNull(bss)) /* should never happen, but just in */
return e; /* case: LETREC [] IN e ==> e */
mapOver(transBinds,bss); /* translate each group of bindings */
for (temp=root; nonNull(tl(bss)); bss=tl(bss)) {
fst(snd(temp)) = hd(bss);
snd(snd(temp)) = ap(LETREC,pair(NIL,e));
temp = snd(snd(temp));
}
fst(snd(temp)) = hd(bss);
return root;
}
/* --------------------------------------------------------------------------
* Transformation of list comprehensions is based on the description in
* `The Implementation of Functional Programming Languages':
*
* [ e | qs ] ++ L => transComp e qs []
* transComp e [] l => e : l
* transComp e ((p<-xs):qs) l => LETREC _h [] = l
* _h (p:_xs) = transComp e qs (_h _xs)
* _h (_:_xs) = _h _xs --if p refutable.
* IN _h xs
* transComp e (b:qs) l => if b then transComp e qs l else l
* transComp e ((p=e1):qs) l => LETREC p = e1 IN transComp e qs l
* ------------------------------------------------------------------------*/
static Cell local transComp(e,qs,l) /* Translate [e | qs] ++ l */
Cell e;
List qs;
Cell l; {
if (nonNull(qs)) {
Cell q = hd(qs);
Cell qs1 = tl(qs);
switch (fst(q)) {
case FROMQUAL : { Cell ld = NIL;
Cell hVar = inventVar();
Cell xsVar = inventVar();
if (refutable(fst(snd(q))))
ld = cons(pair(singleton(
ap(ap(nameCons,
WILDCARD),
xsVar)),
ap(hVar,xsVar)),
ld);
ld = cons(pair(singleton(
ap(ap(nameCons,
fst(snd(q))),
xsVar)),
transComp(e,
qs1,
ap(hVar,xsVar))),
ld);
ld = cons(pair(singleton(nameNil),
l),
ld);
return ap(LETREC,
pair(singleton(pair(hVar,
ld)),
ap(hVar,
translate(snd(snd(q))))));
}
case QWHERE : return ap(LETREC,
pair(remPat(fst(snd(q)),
translate(snd(snd(q))),
NIL),
transComp(e,qs1,l)));
case BOOLQUAL : return ap(COND,
triple(translate(snd(q)),
transComp(e,qs1,l),
l));
}
}
return ap(ap(nameCons,e),l);
}
/* --------------------------------------------------------------------------
* Elimination of pattern bindings:
*
* The following code adopts the definition of irrefutable patterns as given
* in the Haskell report in which only variables, wildcards and ~pat patterns
* are irrefutable. Note that the definition in Peyton Jones also includes
* product constructor functions (e.g. tuples) as irrefutable patterns.
* ------------------------------------------------------------------------*/
static Bool local refutable(pat) /* is pattern refutable (do we need to */
Cell pat; { /* to use a conformality check?) */
Cell c = getHead(pat);
switch (whatIs(c)) {
case ASPAT : return refutable(snd(snd(pat)));
case LAZYPAT :
case VAROPCELL :
case VARIDCELL :
case DICTVAR :
case WILDCARD : return FALSE;
default : return TRUE;
}
}
static Cell local refutePat(pat) /* find pattern to refute in conformality*/
Cell pat; { /* test with pat. */
/* e.g. refPat (x,y) == (_,_) */
/* refPat ~(x,y) == _ etc.. */
switch (whatIs(pat)) {
case ASPAT : return refutePat(snd(snd(pat)));
case FINLIST : { Cell ys = snd(pat);
Cell xs = NIL;
for (; nonNull(ys); ys=tl(ys))
xs = ap(ap(nameCons,refutePat(hd(ys))),xs);
return revOnto(xs,nameNil);
}
case VAROPCELL :
case VARIDCELL :
case DICTVAR :
case WILDCARD :
case LAZYPAT : return WILDCARD;
case INTCELL :
case FLOATCELL :
case STRCELL :
case CHARCELL :
case ADDPAT :
case MULPAT :
case UNIT :
case TUPLE :
case NAME : return pat;
case AP : return ap(refutePat(fun(pat)),refutePat(arg(pat)));
default : internal("refutePat");
return NIL; /*NOTREACHED*/
}
}
#define addEqn(v,val,lds) cons(pair(v,singleton(pair(NIL,val))),lds)
static List local remPat(pat,expr,lds)
Cell pat; /* Produce list of definitions for eqn */
Cell expr; /* pat = expr, including a conformality */
List lds; { /* check if required. */
/* Conformality test (if required):
* pat = expr ==> nv = LETREC confCheck nv@pat = nv
* IN confCheck expr
* remPat1(pat,nv,.....);
*/
if (useConformality && refutable(pat)) {
Cell confVar = inventVar();
Cell nv = inventVar();
Cell locfun = pair(confVar, /* confVar [([nv@refPat],nv)] */
singleton(pair(singleton(ap(ASPAT,
pair(nv,
refutePat(pat)))),
nv)));
lds = addEqn(nv, /* nv = */
ap(LETREC,pair(singleton(locfun), /* LETREC [locfun] */
ap(confVar,expr))), /* IN confVar expr */
lds);
return remPat1(pat,nv,lds);
}
return remPat1(pat,expr,lds);
}
static List local remPat1(pat,expr,lds)
Cell pat; /* Add definitions for: pat = expr to */
Cell expr; /* list of local definitions in lds. */
List lds; {
Cell c;
switch (whatIs(c=getHead(pat))) {
case WILDCARD :
case UNIT :
case INTCELL :
case FLOATCELL :
case STRCELL :
case CHARCELL : break;
case ASPAT : return remPat1(snd(snd(pat)), /* v@pat = expr */
expr,
addEqn(fst(snd(pat)),expr,lds));
case LAZYPAT : { Cell nv;
if (isVar(expr) || isName(expr))
nv = expr;
else {
nv = inventVar();
lds = addEqn(nv,expr,lds);
}
return remPat(snd(pat),nv,lds);
}
case ADDPAT : return addEqn(snd(pat), /* n + k = expr */
ap(ap(nameMinus,expr),
mkInt(intValOf(fst(pat)))),
lds);
case MULPAT : return addEqn(snd(pat), /* c * n = expr */
ap(ap(nameDivide,expr),
mkInt(intValOf(fst(pat)))),
lds);
case FINLIST : return remPat1(mkConsList(snd(pat)),expr,lds);
case DICTVAR : /* shouldn't really occur */
case VARIDCELL :
case VAROPCELL : return addEqn(pat,expr,lds);
case TUPLE :
case NAME : { List ps = getArgs(pat);
Cell nv, sel;
Int i;
if (isVar(expr) || isName(expr))
nv = expr;
else {
nv = inventVar();
lds = addEqn(nv,expr,lds);
}
sel = ap(ap(nameSel,c),nv);
for (i=1; nonNull(ps); ++i, ps=tl(ps))
lds = remPat1(hd(ps),ap(sel,mkInt(i)),lds);
}
break;
default : internal("error in remPat1");
break;
}
return lds;
}
/* --------------------------------------------------------------------------
* Eliminate pattern matching in function definitions -- pattern matching
* compiler:
*
* Based on Wadler's algorithms described in `Implementation of functional
* programming languages'.
*
* During the translation, in preparation for later stages of compilation,
* all local and bound variables are replaced by suitable offsets, and
* locally defined function symbols are given new names (which will
* eventually be their names when lifted to make top level definitions).
* ------------------------------------------------------------------------*/
static Offset freeBegin; /* only variables with offset <= freeBegin are of */
static List freeVars; /* interest as `free' variables */
static List freeFuns; /* List of `free' local functions */
static Cell local pmcTerm(co,sc,e) /* apply pattern matching compiler */
Int co; /* co = current offset */
List sc; /* sc = scope */
Cell e; { /* e = expr to transform */
switch (whatIs(e)) {
case GUARDED : map2Over(pmcPair,co,sc,snd(e));
break;
case LETREC : pmcLetrec(co,sc,snd(e));
break;
case VARIDCELL:
case VAROPCELL:
case DICTVAR : return pmcVar(sc,textOf(e));
case COND : return ap(COND,pmcTriple(co,sc,snd(e)));
case AP : return pmcAp(co,sc,e);
case UNIT :
case TUPLE :
case NAME :
case SELECT :
case DICTCELL :
case CHARCELL :
case INTCELL :
case FLOATCELL:
case STRCELL : break;
default : internal("pmcTerm");
break;
}
return e;
}
static Cell local pmcAp(co,sc,pr) /* apply pattern matching compiler */
Int co; /* to application */
List sc;
Pair pr; {
return pair(pmcTerm(co+1,sc,fst(pr)),
pmcTerm(co,sc,snd(pr)));
}
static Cell local pmcPair(co,sc,pr) /* apply pattern matching compiler */
Int co; /* to a pair of exprs */
List sc;
Pair pr; {
return pair(pmcTerm(co,sc,fst(pr)),
pmcTerm(co,sc,snd(pr)));
}
static Cell local pmcTriple(co,sc,tr) /* apply pattern matching compiler */
Int co; /* to a triple of exprs */
List sc;
Triple tr; {
return triple(pmcTerm(co,sc,fst3(tr)),
pmcTerm(co,sc,snd3(tr)),
pmcTerm(co,sc,thd3(tr)));
}
static Cell local pmcVar(sc,t) /* find translation of variable */
List sc; /* in current scope */
Text t; {
List xs;
Name n;
for (xs=sc; nonNull(xs); xs=tl(xs)) {
Cell x = hd(xs);
if (t==textOf(fst(x)))
if (isOffset(snd(x))) { /* local variable ... */
if (snd(x)<=freeBegin && !cellIsMember(snd(x),freeVars))
freeVars = cons(snd(x),freeVars);
return snd(x);
}
else { /* local function ... */
if (!cellIsMember(snd(x),freeFuns))
freeFuns = cons(snd(x),freeFuns);
return fst3(snd(x));
}
}
if (isNull(n=findName(t))) /* Lookup global name - the only way*/
n = newName(t); /* this (should be able to happen) */
/* is with new global var introduced*/
/* after type check; e.g. remPat1 */
return n;
}
static Void local pmcLetrec(co,sc,e) /* apply pattern matching compiler */
Int co; /* to LETREC, splitting decls into */
List sc; /* two sections */
Pair e; {
List fs = NIL; /* local function definitions */
List vs = NIL; /* local variable definitions */
List ds;
for (ds=fst(e); nonNull(ds); ds=tl(ds)) { /* Split decls into two */
Cell v = fst(hd(ds));
Int arity = length(fst(hd(snd(hd(ds)))));
if (arity==0) { /* Variable declaration */
vs = cons(snd(hd(ds)),vs);
sc = cons(pair(v,mkOffset(++co)),sc);
}
else { /* Function declaration */
fs = cons(triple(inventVar(),mkInt(arity),snd(hd(ds))),fs);
sc = cons(pair(v,hd(fs)),sc);
}
}
vs = rev(vs); /* Put declaration lists back in */
fs = rev(fs); /* original order */
fst(e) = pair(vs,fs); /* Store declaration lists */
map2Over(pmcVarDef,co,sc,vs); /* Translate variable definitions */
map2Proc(pmcFunDef,co,sc,fs); /* Translate function definitions */
snd(e) = pmcTerm(co,sc,snd(e)); /* Translate LETREC body */
freeFuns = diffList(freeFuns,fs); /* Delete any `freeFuns' bound in fs*/
}
static Cell local pmcVarDef(co,sc,vd) /* apply pattern matching compiler */
Int co; /* to variable definition */
List sc;
List vd; { /* vd :: [ ([], rhs) ] */
Cell d = snd(hd(vd));
if (nonNull(tl(vd)) && canFail(d))
return ap(FATBAR,pair(pmcTerm(co,sc,d),
pmcVarDef(co,sc,tl(vd))));
return pmcTerm(co,sc,d);
}
static Void local pmcFunDef(co,sc,fd) /* apply pattern matching compiler */
Int co; /* to function definition */
List sc;
Triple fd; { /* fd :: (Var, Arity, [Alt]) */
Offset saveFreeBegin = freeBegin;
List saveFreeVars = freeVars;
List saveFreeFuns = freeFuns;
Int arity = intOf(snd3(fd));
Cell temp = thd3(fd);
Cell xs;
map1Over(mkSwitch,sc,temp);
freeBegin = mkOffset(co);
freeVars = NIL;
freeFuns = NIL;
temp = match(co+arity,temp,addOffsets(co+arity,co+1,NIL));
thd3(fd) = triple(freeVars,freeFuns,temp);
for (xs=freeVars; nonNull(xs); xs=tl(xs))
if (hd(xs)<=saveFreeBegin && !cellIsMember(hd(xs),saveFreeVars))
saveFreeVars = cons(hd(xs),saveFreeVars);
for (xs=freeFuns; nonNull(xs); xs=tl(xs))
if (!cellIsMember(hd(xs),saveFreeFuns))
saveFreeFuns = cons(hd(xs),saveFreeFuns);
freeBegin = saveFreeBegin;
freeVars = saveFreeVars;
freeFuns = saveFreeFuns;
}
/* --------------------------------------------------------------------------
* Main part of pattern matching compiler: convert lists of Alt to case
* construct:
*
* At each stage, each branch is represented by an element of type:
* Switch ::= ([Pat],Scope,Rhs)
* which indicates that, if we can succeed in matching the given list of
* patterns, then the result will be the indicated Rhs. The Scope component
* has type:
* Scope ::= [(Var,Expr)]
* and provides a mapping from variable names to offsets used in the matching
* process.
*
* ------------------------------------------------------------------------*/
#define switchPats(s) fst3(s)
#define switchSyms(s) snd3(s)
#define switchRhs(s) thd3(s)
#define addSym(v,o,s) switchSyms(s) = cons(pair(v,o),switchSyms(s))
#define matchMore(sw,c,co,us) nonNull(sw)?ap(FATBAR,pair(c,match(co,sw,us))):c
/* There are three kinds of case: */
#define CONDISCR 0 /* Constructor */
#define INTDISCR 1 /* Integer (integer const/n+k) */
#define VARDISCR 2 /* variable (or wildcard) */
#define isConPat(discr) (discrKind(discr)==CONDISCR)
#define isVarPat(discr) (discrKind(discr)==VARDISCR)
#define isIntPat(discr) (discrKind(discr)==INTDISCR)
static Cell local match(co,sws,us) /* produce case statement to select */
Int co; /* between switches in sw, matching */
List sws; /* pats against values at offsets */
List us; { /* given by us. co is the current */
if (nonNull(us)) { /* offset at which new values are */
Cell discr; /* saved */
map1Proc(tidyHdPat,hd(us),sws);
switch (discrKind(discr=hdDiscr(sws))) {
case CONDISCR : return matchCon(co,sws,us,discr);
case INTDISCR : return matchInt(co,sws,us,discr);
case VARDISCR : return matchVar(co,sws,us,discr);
}
}
return joinSw(co,sws);
}
static Void local tidyHdPat(u,s) /* tidy head of pat list in a switch*/
Offset u; /* (Principally eliminating @ pats) */
Cell s; {
Cell p = hd(switchPats(s));
thp:switch (whatIs(p)) {
case ASPAT : addSym(fst(snd(p)),u,s);
p = snd(snd(p));
goto thp;
case LAZYPAT : { Cell nv = inventVar();
switchRhs(s) = ap(LETREC,
pair(remPat(snd(p),nv,NIL),
switchRhs(s)));
p = nv;
}
break;
case FINLIST : p = mkConsList(snd(p));
break;
case STRCELL : { Text t = textOf(p);
Int c;
p = NIL;
while ((c=textToStr(t++)[0])!='\0') {
if (c=='\\' && (c=textToStr(t++)[0])!='\\')
c = 0;
p = ap(consChar(c),p);
}
p = revOnto(p,nameNil);
}
break;
}
hd(switchPats(s)) = p;
}
static Cell local hdDiscr(sws) /* get discriminant of head pattern */
List sws; { /* in first branch of a [Switch]. */
return getHead(hd(fst3(hd(sws))));
}
static Int local discrKind(e) /* find kind of discriminant */
Cell e; {
switch (whatIs(e)) {
case NAME :
case TUPLE :
case UNIT :
case STRCELL : /* shouldn't be here? */
case CHARCELL : return CONDISCR;
case INTCELL :
case ADDPAT :
case MULPAT : return INTDISCR;
case VARIDCELL :
case VAROPCELL :
case DICTVAR :
case WILDCARD : return VARDISCR;
}
internal("discrKind");
return 0;/*NOTREACHED*/
}
Int discrArity(e) /* find arity of discriminant */
Cell e; {
switch (whatIs(e)) {
case NAME : return name(e).arity;
case TUPLE : return tupleOf(e);
case UNIT :
case STRCELL : /* shouldn't be here? */
case FLOATCELL :
case CHARCELL :
case INTCELL : return 0;
case ADDPAT :
case MULPAT :
case VARIDCELL :
case VAROPCELL :
case DICTVAR :
case WILDCARD : return 1;
}
internal("discrArity");
return 0;/*NOTREACHED*/
}
/* --------------------------------------------------------------------------
* Match on variables:
* ------------------------------------------------------------------------*/
static Cell local matchVar(co,sws,us,discr)/* matching against a variable */
Int co; /* does not trigger any evaluation, */
List sws; /* but can extend the scope with a */
List us; /* new binding */
Cell discr; {
List varsw = NIL;
Cell s;
do {
s = hd(sws);
if (discr!=WILDCARD)
addSym(discr,hd(us),s);
switchPats(s) = tl(switchPats(s));
varsw = cons(s,varsw);
sws = tl(sws);
} while (nonNull(sws) && isVarPat(discr=hdDiscr(sws)));
s = match(co,rev(varsw),tl(us));
return matchMore(sws,s,co,us);
}
/* --------------------------------------------------------------------------
* Match on constructors:
* ------------------------------------------------------------------------*/
static Cell local matchCon(co,sws,us,discr) /* matching against constructor*/
Int co;
List sws;
List us;
Cell discr; {
List tab = NIL; /* build table of (discr, [Switch]) */
Cell s;
List ps;
do {
s = hd(sws);
ps = switchPats(s);
ps = appendOnto(getArgs(hd(ps)),tl(ps));
switchPats(s) = ps;
tab = addConTable(discr,s,tab);
sws = tl(sws);
} while (nonNull(sws) && isConPat(discr=hdDiscr(sws)));
s = ap(CASE,pair(hd(us),makeCases(co,rev(tab),tl(us))));
return matchMore(sws,s,co,us);
}
/* type Table a b = [(a, [b])]
*
* addTable :: a -> b -> Table a b -> Table a b
* addTable x y [] = [(x,[y])]
* addTable x y (z@(n,sws):zs)
* | n == x = (n,sws++[y]):zs
* | otherwise = (n,sws):addTable x y zs
*/
static List local addConTable(x,y,tab) /* add element (x,y) to table */
Cell x, y;
List tab; {
if (isNull(tab))
return singleton(pair(x,singleton(y)));
else if (fst(hd(tab))==x)
snd(hd(tab)) = appendOnto(snd(hd(tab)),singleton(y));
else
tl(tab) = addConTable(x,y,tl(tab));
return tab;
}
static Cell local makeCases(co,tab,us) /* build CASE construct for constr */
Int co; /* match */
List tab;
List us; {
List cases;
for (cases=NIL; nonNull(tab); tab=tl(tab)) {
Cell n = fst(hd(tab));
Int co1 = co+discrArity(n);
cases = cons(pair(n,
match(co1,
snd(hd(tab)),
addOffsets(co1,co+1,us))),
cases);
}
return cases;
}
/* --------------------------------------------------------------------------
* Match on integers:
* ------------------------------------------------------------------------*/
static Cell local matchInt(co,sws,us,discr)/* match against integer values */
Int co;
List sws;
List us;
Cell discr; {
List tab = NIL; /* table of (discr, [Switch]) pairs */
Cell s = hd(sws);
Cell cnkPat = NIL; /* current MULPAT or ADDPAT */
List ps;
do {
if (whatIs(discr)==INTCELL) {
if (nonNull(cnkPat))
break;
}
else if (isNull(cnkPat))
cnkPat = discr;
else if (fst(cnkPat)!=fst(discr) || intValOf(cnkPat)!=intValOf(discr))
break;
else
discr = cnkPat;
s = hd(sws);
ps = switchPats(s);
ps = appendOnto(getArgs(hd(ps)),tl(ps));
switchPats(s) = ps;
tab = addConTable(discr,s,tab);
sws = tl(sws);
} while (nonNull(sws) && isIntPat(discr=hdDiscr(sws)));
s = ap(CASE,pair(hd(us),makeCases(co,rev(tab),tl(us))));
return matchMore(sws,s,co,us);
}
/* --------------------------------------------------------------------------
* Miscellaneous:
* ------------------------------------------------------------------------*/
static List local addOffsets(m,n,us) /* addOffsets m n us */
Int m, n; /* = map mkOffset [m,m-1..n] ++ us */
List us; {
for (; m>=n; n++)
us = cons(mkOffset(n),us);
return us;
}
static Cell local mkSwitch(sc,alt) /* convert Alt into Switch: */
List sc; /* mkSwitch sc (ps,r) = (ps,sc,r) */
Pair alt; {
return triple(fst(alt),sc,snd(alt));
}
static Cell local joinSw(co,sws) /* Combine list of Switches into rhs*/
Int co; /* using FATBARs as necessary */
List sws; { /* :: [ ([], Scope, Rhs) ] */
Cell s = hd(sws);
if (nonNull(tl(sws)) && canFail(thd3(s)))
return ap(FATBAR,
pair(pmcTerm(co,snd3(s),thd3(s)),
joinSw(co,tl(sws))));
return pmcTerm(co,snd3(s),thd3(s));
}
static Bool local canFail(rhs) /* Determine if expression (as rhs) */
Cell rhs; { /* might ever be able to fail */
switch (whatIs(rhs)) {
case LETREC : return canFail(snd(snd(rhs)));
case GUARDED : return TRUE; /* could get more sophisticated ..? */
default : return FALSE;
}
}
/* --------------------------------------------------------------------------
* Lambda Lifter: replace local function definitions with new global
* functions. Based on Johnsson's algorithm.
* ------------------------------------------------------------------------*/
static Cell local lift(co,tr,e) /* lambda lift term */
Int co;
List tr;
Cell e; {
switch (whatIs(e)) {
case GUARDED : map2Proc(liftPair,co,tr,snd(e));
break;
case FATBAR : liftPair(co,tr,snd(e));
break;
case CASE : map2Proc(liftAlt,co,tr,snd(snd(e)));
break;
case COND : liftTriple(co,tr,snd(e));
break;
case AP : liftAp(co,tr,e);
break;
case VAROPCELL :
case VARIDCELL :
case DICTVAR : return liftVar(tr,e);
case LETREC : return liftLetrec(co,tr,e);
case UNIT :
case TUPLE :
case NAME :
case SELECT :
case DICTCELL :
case INTCELL :
case FLOATCELL :
case STRCELL :
case OFFSET :
case CHARCELL : break;
default : internal("Bad cterm");
break;
}
return e;
}
static Void local liftAp(co,tr,pr) /* lift application */
Int co;
List tr;
Pair pr; {
fst(pr) = lift(co+1,tr,fst(pr));
snd(pr) = lift(co,tr,snd(pr));
}
static Void local liftPair(co,tr,pr) /* lift pair of terms */
Int co;
List tr;
Pair pr; {
fst(pr) = lift(co,tr,fst(pr));
snd(pr) = lift(co,tr,snd(pr));
}
static Void local liftTriple(co,tr,e) /* lift triple of terms */
Int co;
List tr;
Triple e; {
fst3(e) = lift(co,tr,fst3(e));
snd3(e) = lift(co,tr,snd3(e));
thd3(e) = lift(co,tr,thd3(e));
}
static Void local liftAlt(co,tr,pr) /* lift (discr,case) pair */
Int co;
List tr;
Cell pr; { /* pr :: (discr,case) */
snd(pr) = lift(co+discrArity(fst(pr)), tr, snd(pr));
}
static Cell local liftVar(tr,e) /* lift variable */
List tr;
Cell e; {
Text t = textOf(e);
while (nonNull(tr) && textOf(fst(hd(tr)))!=t)
tr = tl(tr);
if (isNull(tr))
internal("Local function not found");
return snd(hd(tr));
}
static Cell local liftLetrec(co,tr,e) /* lift letrec term */
Int co;
List tr;
Cell e; {
List vs = fst(fst(snd(e)));
List fs = snd(fst(snd(e)));
List fds;
co += length(vs);
solve(fs);
for (fds=fs; nonNull(fds); fds=tl(fds)) {
Triple fundef = hd(fds);
List fvs = fst3(thd3(fundef));
Cell n = newName(textOf(fst3(fundef)));
Cell e0;
for (e0=n; nonNull(fvs); fvs=tl(fvs))
e0 = ap(e0,hd(fvs));
tr = cons(pair(fst3(fundef),e0),tr);
fst3(fundef) = n;
}
map2Proc(liftFundef,co,tr,fs);
if (isNull(vs))
return lift(co,tr,snd(snd(e)));
map2Over(lift,co,tr,vs);
fst(snd(e)) = vs;
snd(snd(e)) = lift(co,tr,snd(snd(e)));
return e;
}
static Void local liftFundef(co,tr,fd) /* lift function definition */
Int co;
List tr;
Triple fd; {
Int arity = intOf(snd3(fd));
newGlobalFunction(fst3(fd), /* name */
arity, /* arity */
fst3(thd3(fd)), /* free variables */
co+arity, /* current offset */
lift(co+arity,tr,thd3(thd3(fd)))); /* lifted case */
}
/* Each element in a list of fundefs has the form: (v,a,(fvs,ffs,rhs))
* where fvs is a list of free variables which must be added as extra
* parameters to the lifted version of function v,
* ffs is a list of fundefs defined either in the group of definitions
* including v, or in some outer LETREC binding.
*
* In order to determine the correct value for fvs, we must include:
* - all variables explicitly appearing in the body rhs (this much is
* achieved in pmcVar).
* - all variables required for lifting those functions appearing in ffs.
* - If f is a fundef in an enclosing group of definitions then the
* correct list of variables to include with each occurrence of f will
* have already been calculated and stored in the fundef f. We simply
* take the union of this list with fvs.
* - If f is a fundef in the same group of bindings as v, then we iterate
* to find the required solution.
*/
#ifdef DEBUG_CODE
static Void dumpFundefs(fs)
List fs; {
printf("Dumping Fundefs:\n");
for (; nonNull(fs); fs=tl(fs)) {
Cell t = hd(fs);
List fvs = fst3(thd3(t));
List ffs = snd3(thd3(t));
printf("Var \"%s\", arity %d:\n",textToStr(textOf(fst3(t))),
intOf(snd3(t)));
printf("Free variables: ");
printExp(stdout,fvs);
putchar('\n');
printf("Local functions: ");
for (; nonNull(ffs); ffs=tl(ffs)) {
printExp(stdout,fst3(hd(ffs)));
printf(" ");
}
putchar('\n');
}
printf("----------------\n");
}
#endif
static Void local solve(fs) /* Solve eqns for lambda-lifting */
List fs; { /* of local function definitions */
Bool hasChanged;
List fs0, fs1;
/* initial pass distinguishes between those functions defined in fs and
* those defined in enclosing LETREC clauses ...
*/
for (fs0=fs; nonNull(fs0); fs0=tl(fs0)) {
List fvs = fst3(thd3(hd(fs0)));
List ffs = NIL;
for (fs1=snd3(thd3(hd(fs0))); nonNull(fs1); fs1=tl(fs1)) {
if (cellIsMember(hd(fs1),fs)) /* function in same LETREC*/
ffs = cons(hd(fs1),ffs);
else { /* enclosing letrec */
List fvs1 = fst3(thd3(hd(fs1)));
for (; nonNull(fvs1); fvs1=tl(fvs1))
if (!cellIsMember(hd(fvs1),fvs))
fvs = cons(hd(fvs1),fvs);
}
}
fst3(thd3(hd(fs0))) = fvs;
snd3(thd3(hd(fs0))) = ffs;
}
/* now that the ffs component of each fundef in fs has been restricted
* to a list of fundefs in fs, we iterate to add any extra free variables
* that are needed (in effect, calculating the reflexive transitive
* closure of the local call graph of fs).
*/
do {
hasChanged = FALSE;
for (fs0=fs; nonNull(fs0); fs0=tl(fs0)) {
List fvs0 = fst3(thd3(hd(fs0)));
for (fs1=snd3(thd3(hd(fs0))); nonNull(fs1); fs1=tl(fs1))
if (hd(fs1)!=hd(fs0)) {
List fvs1 = fst3(thd3(hd(fs1)));
for (; nonNull(fvs1); fvs1=tl(fvs1))
if (!cellIsMember(hd(fvs1),fvs0)) {
hasChanged = TRUE;
fvs0 = cons(hd(fvs1),fvs0);
}
}
if (hasChanged) fst3(thd3(hd(fs0))) = fvs0;
}
} while (hasChanged);
}
/* --------------------------------------------------------------------------
* Pre-compiler: Uses output from lambda lifter to produce terms suitable
* for input to code generator.
* ------------------------------------------------------------------------*/
static List extraVars; /* List of additional vars to add to function */
static Int numExtraVars; /* Length of extraVars */
static Int localOffset; /* offset value used in original definition */
static Int localArity; /* arity of function being compiled w/o extras */
/* --------------------------------------------------------------------------
* Arrangement of arguments on stack prior to call of
* n x_1 ... x_e y_1 ... y_a
* where
* e = numExtraVars, x_1,...,x_e are the extra params to n
* a = localArity of n, y_1,...,y_a are the original params
*
* offset 1 : y_a } STACKPART1
* .. }
* offset a : y_1 }
*
* offset 1+a : x_e } STACKPART2
* .. }
* offset e+a : x_1 }
*
* offset e+a+1 : used for temporary results ... STACKPART3
* ..
* ..
*
* In the original defn for n, the offsets in STACKPART1 and STACKPART3
* are contiguous. To add the extra parameters we need to insert the
* offsets in STACKPART2, adjusting offset values as necessary.
* ------------------------------------------------------------------------*/
static Cell local preComp(e) /* Adjust output from compiler to */
Cell e; { /* include extra parameters */
switch (whatIs(e)) {
case GUARDED : mapOver(preCompPair,snd(e));
break;
case LETREC : mapOver(preComp,fst(snd(e)));
snd(snd(e)) = preComp(snd(snd(e)));
break;
case COND : return ap(COND,preCompTriple(snd(e)));
case FATBAR : return ap(FATBAR,preCompPair(snd(e)));
case AP : return preCompPair(e);
case CASE : fst(snd(e)) = preComp(fst(snd(e)));
mapProc(preCompCase,snd(snd(e)));
break;
case OFFSET : return preCompOffset(offsetOf(e));
case UNIT :
case TUPLE :
case NAME :
case SELECT :
case DICTCELL :
case INTCELL :
case FLOATCELL :
case STRCELL :
case CHARCELL : break;
default : internal("preComp");
}
return e;
}
static Cell local preCompPair(e) /* Apply preComp to pair of Exprs */
Pair e; {
return pair(preComp(fst(e)),
preComp(snd(e)));
}
static Cell local preCompTriple(e) /* Apply preComp to triple of Exprs */
Triple e; {
return triple(preComp(fst3(e)),
preComp(snd3(e)),
preComp(thd3(e)));
}
static Void local preCompCase(e) /* Apply preComp to (Discr,Expr) */
Pair e; {
snd(e) = preComp(snd(e));
}
static Cell local preCompOffset(n) /* Determine correct offset value */
Int n; { /* for local variable/function arg. */
if (n>localOffset-localArity)
if (n>localOffset) /* STACKPART3 */
return mkOffset(n-localOffset+localArity+numExtraVars);
else /* STACKPART1 */
return mkOffset(n-localOffset+localArity);
else { /* STACKPART2 */
List fvs = extraVars;
Int i = localArity+numExtraVars;
for (; nonNull(fvs) && offsetOf(hd(fvs))!=n; --i)
fvs=tl(fvs);
return mkOffset(i);
}
}
/* --------------------------------------------------------------------------
* Main entry points to compiler:
* ------------------------------------------------------------------------*/
Void compileExp() { /* compile input expression */
compiler(RESET);
inputExpr = lift(0,NIL,pmcTerm(0,NIL,translate(inputExpr)));
extraVars = NIL;
numExtraVars = 0;
localOffset = 0;
localArity = 0;
inputCode = codeGen(NIL,0,preComp(inputExpr));
inputExpr = NIL;
}
Void compileDefns() { /* compile script definitions */
Target t = length(valDefns) + length(overDefns);
Target i = 0;
setGoal("Compiling",t);
for (; nonNull(valDefns); valDefns=tl(valDefns)) {
mapProc(compileGlobalFunction,transBinds(hd(valDefns)));
soFar(i++);
}
for (; nonNull(overDefns); overDefns=tl(overDefns)) {
compileMemberFunction(hd(overDefns));
soFar(i++);
}
done();
}
static Void local compileGlobalFunction(bind)
Pair bind; {
Name n = findName(textOf(fst(bind)));
List defs = snd(bind);
Int arity = length(fst(hd(defs)));
if (isNull(n))
internal("no such name in compileGlobalFunction");
compiler(RESET);
map1Over(mkSwitch,NIL,defs);
newGlobalFunction(n,
arity,
NIL,
arity,
lift(arity,
NIL,
match(arity,
defs,
addOffsets(arity,1,NIL))));
}
static Void local compileMemberFunction(n)
Name n; {
List defs = name(n).defn;
Int arity = length(fst(hd(defs)));
compiler(RESET);
mapProc(transAlt,defs);
map1Over(mkSwitch,NIL,defs);
newGlobalFunction(n,
arity,
NIL,
arity,
lift(arity,
NIL,
match(arity,
defs,
addOffsets(arity,1,NIL))));
}
static Void local newGlobalFunction(n,arity,fvs,co,e)
Name n;
Int arity;
List fvs;
Int co;
Cell e; {
extraVars = fvs;
numExtraVars = length(extraVars);
localOffset = co;
localArity = arity;
name(n).arity = arity+numExtraVars;
name(n).code = codeGen(n,name(n).arity,preComp(e));
name(n).defn = NIL;
}
/* --------------------------------------------------------------------------
* Compiler control:
* ------------------------------------------------------------------------*/
Void compiler(what)
Int what; {
switch (what) {
case INSTALL :
case RESET : freeVars = NIL;
freeFuns = NIL;
freeBegin = mkOffset(0);
extraVars = NIL;
numExtraVars = 0;
localOffset = 0;
localArity = 0;
break;
case MARK : mark(freeVars);
mark(freeFuns);
mark(extraVars);
break;
}
}
/*-------------------------------------------------------------------------*/